package errors

import (
	"fmt"
)

// ErrorCode 错误代码枚举
type ErrorCode int

const (
	// General errors
	UnknownError ErrorCode = iota
	InvalidParameter
	InvalidConfiguration
	
	// Database errors
	DatabaseConnectionError
	DatabaseQueryError
	DatabaseTransactionError
	
	// Mapper errors
	MapperNotFound
	StatementNotFound
	InvalidStatement
	
	// Plugin errors
	PluginError
	PluginNotFound
	
	// Binding errors
	ParameterBindingError
	ResultMappingError
	
	// XML parsing errors
	XMLParseError
	XMLValidationError
)

// GoBatisError 统一的错误类型
type GoBatisError struct {
	Code    ErrorCode
	Message string
	Cause   error
	Context map[string]interface{}
}

// Error 实现 error 接口
func (e *GoBatisError) Error() string {
	if e.Cause != nil {
		return fmt.Sprintf("[%d] %s: %v", e.Code, e.Message, e.Cause)
	}
	return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}

// Unwrap 实现错误链
func (e *GoBatisError) Unwrap() error {
	return e.Cause
}

// Is 检查错误类型
func (e *GoBatisError) Is(target error) bool {
	if t, ok := target.(*GoBatisError); ok {
		return e.Code == t.Code
	}
	return false
}

// WithContext 添加上下文信息
func (e *GoBatisError) WithContext(key string, value interface{}) *GoBatisError {
	if e.Context == nil {
		e.Context = make(map[string]interface{})
	}
	e.Context[key] = value
	return e
}

// GetContext 获取上下文信息
func (e *GoBatisError) GetContext(key string) (interface{}, bool) {
	if e.Context == nil {
		return nil, false
	}
	value, exists := e.Context[key]
	return value, exists
}

// New 创建新的 GoBatis 错误
func New(code ErrorCode, message string) *GoBatisError {
	return &GoBatisError{
		Code:    code,
		Message: message,
		Context: make(map[string]interface{}),
	}
}

// Wrap 包装现有错误
func Wrap(code ErrorCode, message string, cause error) *GoBatisError {
	return &GoBatisError{
		Code:    code,
		Message: message,
		Cause:   cause,
		Context: make(map[string]interface{}),
	}
}

// Wrapf 格式化包装错误
func Wrapf(code ErrorCode, cause error, format string, args ...interface{}) *GoBatisError {
	return &GoBatisError{
		Code:    code,
		Message: fmt.Sprintf(format, args...),
		Cause:   cause,
		Context: make(map[string]interface{}),
	}
}

// 预定义的错误创建函数

// NewDatabaseError 创建数据库错误
func NewDatabaseError(message string, cause error) *GoBatisError {
	return Wrap(DatabaseConnectionError, message, cause)
}

// NewQueryError 创建查询错误
func NewQueryError(message string, cause error) *GoBatisError {
	return Wrap(DatabaseQueryError, message, cause)
}

// NewMapperError 创建 Mapper 错误
func NewMapperError(message string) *GoBatisError {
	return New(MapperNotFound, message)
}

// NewStatementError 创建语句错误
func NewStatementError(statementId string) *GoBatisError {
	return New(StatementNotFound, fmt.Sprintf("statement not found: %s", statementId)).
		WithContext("statementId", statementId)
}

// NewParameterBindingError 创建参数绑定错误
func NewParameterBindingError(message string, cause error) *GoBatisError {
	return Wrap(ParameterBindingError, message, cause)
}

// NewResultMappingError 创建结果映射错误
func NewResultMappingError(message string, cause error) *GoBatisError {
	return Wrap(ResultMappingError, message, cause)
}

// NewXMLParseError 创建 XML 解析错误
func NewXMLParseError(message string, cause error) *GoBatisError {
	return Wrap(XMLParseError, message, cause)
}

// NewPluginError 创建插件错误
func NewPluginError(message string, cause error) *GoBatisError {
	return Wrap(PluginError, message, cause)
}

// NewConfigurationError 创建配置错误
func NewConfigurationError(message string) *GoBatisError {
	return New(InvalidConfiguration, message)
}

// IsErrorCode 检查错误是否为指定类型
func IsErrorCode(err error, code ErrorCode) bool {
	if gobatisErr, ok := err.(*GoBatisError); ok {
		return gobatisErr.Code == code
	}
	return false
}

// GetErrorCode 获取错误代码
func GetErrorCode(err error) ErrorCode {
	if gobatisErr, ok := err.(*GoBatisError); ok {
		return gobatisErr.Code
	}
	return UnknownError
}

// ErrorCodeString 获取错误代码的字符串表示
func (c ErrorCode) String() string {
	switch c {
	case UnknownError:
		return "UnknownError"
	case InvalidParameter:
		return "InvalidParameter"
	case InvalidConfiguration:
		return "InvalidConfiguration"
	case DatabaseConnectionError:
		return "DatabaseConnectionError"
	case DatabaseQueryError:
		return "DatabaseQueryError"
	case DatabaseTransactionError:
		return "DatabaseTransactionError"
	case MapperNotFound:
		return "MapperNotFound"
	case StatementNotFound:
		return "StatementNotFound"
	case InvalidStatement:
		return "InvalidStatement"
	case PluginError:
		return "PluginError"
	case PluginNotFound:
		return "PluginNotFound"
	case ParameterBindingError:
		return "ParameterBindingError"
	case ResultMappingError:
		return "ResultMappingError"
	case XMLParseError:
		return "XMLParseError"
	case XMLValidationError:
		return "XMLValidationError"
	default:
		return fmt.Sprintf("UnknownErrorCode(%d)", c)
	}
}